package com.bainaeco.framework.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;

import com.bainaeco.framework.exception.ForbiddenException;
import com.bainaeco.framework.exception.InvalidArgumentException;
import com.bainaeco.framework.exception.PageNotFoundException;

/**
 * http request common class
 * 
 * @author edwin.zhou
 * 
 */
public class HttpClientUtils {

	private static String DEFAULT_CHARSET = "UTF-8";

	private static final int CONNECTION_TIMEOUT = 5000;
	private static final int SO_TIMEOUT = 10000;
	
	private static final int BUFFER_SIZE = 4096;

	public static void imageDownloader(String url,String path) throws Exception {

		HttpParams httpParams = new BasicHttpParams();
		// 设置连接超时时间(单位毫秒)
		HttpConnectionParams.setConnectionTimeout(httpParams, CONNECTION_TIMEOUT);
		// 设置读数据超时时间(单位毫秒)
		HttpConnectionParams.setSoTimeout(httpParams, SO_TIMEOUT);

		HttpClient httpclient = new DefaultHttpClient(httpParams);

		if (url.toLowerCase().startsWith("https")) {
			httpclient = WebClientDevWrapper.wrapClient(httpclient);
		}

		// Prepare a request object
		HttpGet httpget = new HttpGet(url);

		// Execute the request
		HttpResponse response = httpclient.execute(httpget);

		// Examine the response status
		// System.out.println(response.getStatusLine());
		int statusCode = response.getStatusLine().getStatusCode();
		if (statusCode != HttpStatus.SC_OK) {
			processErrorStatus(url, statusCode);
		}

		// Get hold of the response entity
		HttpEntity entity = response.getEntity();

		// If the response does not enclose an entity, there is no need
		// to worry about connection release
		if (entity != null) {
			InputStream instream = entity.getContent();
			File file = new File(path);
			FileOutputStream fos = new FileOutputStream(file);
			try {
				byte[] buffer = new byte[BUFFER_SIZE];
				int len = -1;
		        while((len = instream.read(buffer) )!= -1){
		            fos.write(buffer, 0, len);
		        }
//				String line = null;
//				while ((line = reader.readLine()) != null) {
//
//					result.append(line);
//				}

			} catch (IOException ex) {

				// In case of an IOException the connection will be released
				// back to the connection manager automatically
				throw ex;

			} catch (RuntimeException ex) {

				// In case of an unexpected exception you may want to abort
				// the HTTP request in order to shut down the underlying
				// connection and release it back to the connection manager.
				httpget.abort();
				throw ex;

			} finally {

				// Closing the input stream will trigger connection release
				instream.close();
				fos.close();

			}

			// When HttpClient instance is no longer needed,
			// shut down the connection manager to ensure
			// immediate deallocation of all system resources
			httpclient.getConnectionManager().shutdown();
		}
	}
	
	public static String getMethodRequest(String url) throws Exception {

		StringBuilder result = new StringBuilder();

		HttpParams httpParams = new BasicHttpParams();
		// 设置连接超时时间(单位毫秒)
		HttpConnectionParams.setConnectionTimeout(httpParams, CONNECTION_TIMEOUT);
		// 设置读数据超时时间(单位毫秒)
		HttpConnectionParams.setSoTimeout(httpParams, SO_TIMEOUT);

		HttpClient httpclient = new DefaultHttpClient(httpParams);

		if (url.toLowerCase().startsWith("https")) {
			httpclient = WebClientDevWrapper.wrapClient(httpclient);
		}

		// Prepare a request object
		HttpGet httpget = new HttpGet(url);

		// Execute the request
		HttpResponse response = httpclient.execute(httpget);

		// Examine the response status
		// System.out.println(response.getStatusLine());
		int statusCode = response.getStatusLine().getStatusCode();
		if (statusCode != HttpStatus.SC_OK) {
			processErrorStatus(url, statusCode);
		}

		// Get hold of the response entity
		HttpEntity entity = response.getEntity();

		// If the response does not enclose an entity, there is no need
		// to worry about connection release
		if (entity != null) {
			InputStream instream = entity.getContent();
			try {

				BufferedReader reader = new BufferedReader(new InputStreamReader(instream, DEFAULT_CHARSET));

				String line = null;
				while ((line = reader.readLine()) != null) {

					result.append(line);
				}

			} catch (IOException ex) {

				// In case of an IOException the connection will be released
				// back to the connection manager automatically
				throw ex;

			} catch (RuntimeException ex) {

				// In case of an unexpected exception you may want to abort
				// the HTTP request in order to shut down the underlying
				// connection and release it back to the connection manager.
				httpget.abort();
				throw ex;

			} finally {

				// Closing the input stream will trigger connection release
				instream.close();

			}

			// When HttpClient instance is no longer needed,
			// shut down the connection manager to ensure
			// immediate deallocation of all system resources
			httpclient.getConnectionManager().shutdown();
		}

		return result.toString();
	}

	public static String postMethodRequest(String url, Map<String, String> params) throws Exception {

		StringBuilder result = new StringBuilder();

		HttpParams httpParams = new BasicHttpParams();
		// 设置连接超时时间(单位毫秒)
		HttpConnectionParams.setConnectionTimeout(httpParams, CONNECTION_TIMEOUT);
		// 设置读数据超时时间(单位毫秒)
		HttpConnectionParams.setSoTimeout(httpParams, SO_TIMEOUT);

		HttpClient httpclient = new DefaultHttpClient(httpParams);

		if (url.toLowerCase().startsWith("https")) {
			httpclient = WebClientDevWrapper.wrapClient(httpclient);
		}

		// Prepare a request object
		HttpPost httppost = new HttpPost(url);

		if (params != null && !params.isEmpty()) {
			Set<Map.Entry<String, String>> paramsSet = params.entrySet();
			List<NameValuePair> nvps = new ArrayList<NameValuePair>();

			for (Map.Entry<String, String> entry : paramsSet) {
				nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
			}

			httppost.setEntity(new UrlEncodedFormEntity(nvps, DEFAULT_CHARSET));
		}

		// Execute the request
		HttpResponse response = httpclient.execute(httppost);

		// Examine the response status
		// System.out.println(response.getStatusLine());
		int statusCode = response.getStatusLine().getStatusCode();
		if (statusCode != HttpStatus.SC_OK) {
			processErrorStatus(url, statusCode);
		}

		// Get hold of the response entity
		HttpEntity entity = response.getEntity();

		// If the response does not enclose an entity, there is no need
		// to worry about connection release
		if (entity != null) {
			InputStream instream = entity.getContent();
			try {

				BufferedReader reader = new BufferedReader(new InputStreamReader(instream));

				String line = null;
				while ((line = reader.readLine()) != null) {

					result.append(line);
				}

			} catch (IOException ex) {

				// In case of an IOException the connection will be released
				// back to the connection manager automatically
				throw ex;

			} catch (RuntimeException ex) {

				// In case of an unexpected exception you may want to abort
				// the HTTP request in order to shut down the underlying
				// connection and release it back to the connection manager.
				httppost.abort();
				throw ex;

			} finally {

				// Closing the input stream will trigger connection release
				instream.close();

			}

			// When HttpClient instance is no longer needed,
			// shut down the connection manager to ensure
			// immediate deallocation of all system resources
			httpclient.getConnectionManager().shutdown();
		}

		return result.toString();
	}

	public static String postMethodRequest(String url, Map<String, String> params, int connectionTimeout, int soTimeout) throws Exception {

		StringBuilder result = new StringBuilder();

		HttpParams httpParams = new BasicHttpParams();
		// 设置连接超时时间(单位毫秒)
		HttpConnectionParams.setConnectionTimeout(httpParams, CONNECTION_TIMEOUT);
		// 设置读数据超时时间(单位毫秒)
		HttpConnectionParams.setSoTimeout(httpParams, SO_TIMEOUT);

		HttpClient httpclient = new DefaultHttpClient(httpParams);

		if (url.toLowerCase().startsWith("https")) {
			httpclient = WebClientDevWrapper.wrapClient(httpclient);
		}

		// Prepare a request object
		HttpPost httppost = new HttpPost(url);

		if (params != null && !params.isEmpty()) {
			Set<Map.Entry<String, String>> paramsSet = params.entrySet();
			List<NameValuePair> nvps = new ArrayList<NameValuePair>();

			for (Map.Entry<String, String> entry : paramsSet) {
				nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
			}

			httppost.setEntity(new UrlEncodedFormEntity(nvps, DEFAULT_CHARSET));
		}

		// Execute the request
		HttpResponse response = httpclient.execute(httppost);

		// Examine the response status
		// System.out.println(response.getStatusLine());
		int statusCode = response.getStatusLine().getStatusCode();
		if (statusCode != HttpStatus.SC_OK) {
			processErrorStatus(url, statusCode);
		}

		// Get hold of the response entity
		HttpEntity entity = response.getEntity();

		// If the response does not enclose an entity, there is no need
		// to worry about connection release
		if (entity != null) {
			InputStream instream = entity.getContent();
			try {

				BufferedReader reader = new BufferedReader(new InputStreamReader(instream));

				String line = null;
				while ((line = reader.readLine()) != null) {

					result.append(line);
				}

			} catch (IOException ex) {

				// In case of an IOException the connection will be released
				// back to the connection manager automatically
				throw ex;

			} catch (RuntimeException ex) {

				// In case of an unexpected exception you may want to abort
				// the HTTP request in order to shut down the underlying
				// connection and release it back to the connection manager.
				httppost.abort();
				throw ex;

			} finally {

				// Closing the input stream will trigger connection release
				instream.close();

			}

			// When HttpClient instance is no longer needed,
			// shut down the connection manager to ensure
			// immediate deallocation of all system resources
			httpclient.getConnectionManager().shutdown();
		}

		return result.toString();
	}

	public static String xmlPostMethodRequest(String url, String xml) throws Exception {
		HttpParams httpParams = new BasicHttpParams();
		// 设置连接超时时间(单位毫秒)
		HttpConnectionParams.setConnectionTimeout(httpParams, CONNECTION_TIMEOUT);
		// 设置读数据超时时间(单位毫秒)
		HttpConnectionParams.setSoTimeout(httpParams, SO_TIMEOUT);

		HttpClient httpclient = new DefaultHttpClient(httpParams);

		if (url.toLowerCase().startsWith("https")) {
			httpclient = WebClientDevWrapper.wrapClient(httpclient);
		}

		HttpPost post = new HttpPost(url);
		// post.setHeader("Content-Length", String.valueOf(xml.length()));
		post.setHeader("Content-Type", "application/xml; charset=utf-8");

		StringEntity xmlEntity = new StringEntity(xml, "UTF-8");
		xmlEntity.setContentType("application/xml");
		post.setEntity(xmlEntity);
		HttpResponse response = httpclient.execute(post);

		// Examine the response status
		int statusCode = response.getStatusLine().getStatusCode();
		if (statusCode != HttpStatus.SC_OK) { // 200
			processErrorStatus(url, statusCode);
		}

		String result = EntityUtils.toString(response.getEntity(),"UTF-8");

		return result;
	}

	public static String jsonPostMethodRequest(String url, String json) throws Exception {
		HttpParams httpParams = new BasicHttpParams();
		// 设置连接超时时间(单位毫秒)
		HttpConnectionParams.setConnectionTimeout(httpParams, CONNECTION_TIMEOUT);
		// 设置读数据超时时间(单位毫秒)
		HttpConnectionParams.setSoTimeout(httpParams, SO_TIMEOUT);

		HttpClient httpclient = new DefaultHttpClient(httpParams);

		if (url.toLowerCase().startsWith("https")) {
			httpclient = WebClientDevWrapper.wrapClient(httpclient);
		}

		HttpPost post = new HttpPost(url);
		// post.setHeader("Content-Length", String.valueOf(xml.length()));
		post.setHeader("Content-Type", "application/json; charset=utf-8");
		StringEntity xmlEntity = new StringEntity(json);
		xmlEntity.setContentEncoding("UTF-8");
		post.setEntity(xmlEntity);

		HttpResponse response = httpclient.execute(post);

		// Examine the response status
		int statusCode = response.getStatusLine().getStatusCode();
		if (statusCode != HttpStatus.SC_OK) { // 200
			processErrorStatus(url, statusCode);
		}

		String result = EntityUtils.toString(response.getEntity());

		return result;
	}

	private static void processErrorStatus(String url, int statusCode) throws Exception {
		switch (statusCode) {
		case HttpStatus.SC_BAD_REQUEST:
			throw new InvalidArgumentException("Execute a request failed: " + url + " response status code " + statusCode);
		case HttpStatus.SC_FORBIDDEN:
			throw new ForbiddenException("Execute a request failed: " + url + " response status code " + statusCode);
		case HttpStatus.SC_NOT_FOUND:
			throw new PageNotFoundException("Execute a request failed: " + url + " response status code " + statusCode);
		default:
			throw new Exception("Execute a request failed: " + url + " response status code " + statusCode);
		}
	}

	public static void main(String[] args) throws Exception {
		String description = HttpClientUtils.getMethodRequest("https://itunes.apple.com/lookup?id=406170487");
		System.out.println(description.replaceAll("📌", ""));
		// System.out.println("result:" + HttpClientUtils.getMethodRequest("https://itunes.apple.com/lookup?id=406170487"));
	}
}
